// SPDX-License-Identifier: Mulan PSL v2
/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This software is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

use std::{
    cell::Cell,
    ffi::{c_int, c_void},
};

use tracing::{debug, info};

use cudax::cublaslt::*;
use xgpu_common::{
    ipc::message::{Argument, ArgumentFlag, Request},
    utils::api_name::ApiFuncName,
};

use crate::{agent, fault_guard::virt, hook::cublaslt::CublasLtApi};

thread_local! {
    static THREAD_SCALE_TYPE: Cell<u32> = const { Cell::new(0u32) };
}

fn get_scale_type_size(scale_type: u32) -> usize {
    #[allow(non_upper_case_globals)]
    match scale_type {
        // 1-byte types
        cudaDataType_t_CUDA_R_8I
        | cudaDataType_t_CUDA_R_8U
        | cudaDataType_t_CUDA_C_8I
        | cudaDataType_t_CUDA_C_8U
        | cudaDataType_t_CUDA_R_8F_E4M3
        | cudaDataType_t_CUDA_R_8F_E5M2 => 1,

        // 2-byte types
        cudaDataType_t_CUDA_R_16F
        | cudaDataType_t_CUDA_R_16BF
        | cudaDataType_t_CUDA_R_16I
        | cudaDataType_t_CUDA_R_16U => 2,

        // 4-byte types (real 32-bit + complex 16-bit)
        cudaDataType_t_CUDA_R_32F
        | cudaDataType_t_CUDA_R_32I
        | cudaDataType_t_CUDA_R_32U
        | cudaDataType_t_CUDA_C_16F
        | cudaDataType_t_CUDA_C_16BF
        | cudaDataType_t_CUDA_C_16I
        | cudaDataType_t_CUDA_C_16U => 4,

        // 8-byte types (real 64-bit + complex 32-bit)
        cudaDataType_t_CUDA_R_64F
        | cudaDataType_t_CUDA_R_64I
        | cudaDataType_t_CUDA_R_64U
        | cudaDataType_t_CUDA_C_32F
        | cudaDataType_t_CUDA_C_32I
        | cudaDataType_t_CUDA_C_32U => 8,

        // 16-byte types (complex 64-bit)
        cudaDataType_t_CUDA_C_64F | cudaDataType_t_CUDA_C_64I | cudaDataType_t_CUDA_C_64U => 16,

        // 4-bit types and any other unknown type → default to 8
        _ => 8,
    }
}
pub struct CublasLtApiImpl;

impl CublasLtApi for CublasLtApiImpl {
    fn cublasLtCreate(&self, light_handle: *mut cublasLtHandle_t) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtCreate");
        debug!(
            "before: lt_handle ptr:{:p},  *lt_handle:{:?}",
            light_handle,
            unsafe { *light_handle }
        );

        let mut light_handle_u64 = unsafe { *light_handle } as u64;

        let req = Request::with_args(
            ApiFuncName::FuncCublasltcreate as u64,
            vec![Argument::from_mut(
                &mut light_handle_u64,
                ArgumentFlag::ARG_OUT | ArgumentFlag::ARG_VIRT,
            )],
        );
        let request_id = req.request_id();
        let res = agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed");
        debug!(
            "after: lt_handle ptr:{:p},  *lt_handle:{:?}",
            light_handle,
            unsafe { *light_handle }
        );

        unsafe {
            *light_handle = light_handle_u64 as cublasLtHandle_t;

            virt::handle_insert(
                *light_handle as *mut c_void,
                *light_handle as *mut c_void,
                0,
            )
            .expect("handle_insert failed");
            virt::req_id_vhandle_insert(request_id, *light_handle as *mut c_void)
                .expect("req_id_vhandle_insert failed");
        }
        res
    }

    fn cublasLtDestroy(&self, light_handle: cublasLtHandle_t) -> cublasStatus_t {
        info!("[--Hooked--] api_name: cublasLtDestroy");

        let light_handle_u64 = virt::handle_map(light_handle as *mut c_void)
            .expect("handle_map failed") as cublasLtHandle_t as u64;

        let req = Request::with_args(
            ApiFuncName::FuncCublasltdestroy as u64,
            vec![Argument::from_ref(
                &light_handle_u64,
                ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
            )],
        );
        agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed")
    }

    fn cublasLtMatmul(
        &self,
        light_handle: cublasLtHandle_t,
        compute_desc: cublasLtMatmulDesc_t,
        alpha: *const c_void,
        a: *const c_void,
        a_desc: cublasLtMatrixLayout_t,
        b: *const c_void,
        b_desc: cublasLtMatrixLayout_t,
        beta: *const c_void,
        c: *const c_void,
        c_desc: cublasLtMatrixLayout_t,
        d: *mut c_void,
        d_desc: cublasLtMatrixLayout_t,
        algo: *const cublasLtMatmulAlgo_t,
        workspace: *mut c_void,
        workspace_size_in_bytes: usize,
        stream: cudaStream_t,
    ) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtMatmul");

        let light_handle_u64 = virt::handle_map(light_handle as *mut c_void)
            .expect("handle_map failed") as cublasLtHandle_t as u64;
        let compute_desc_u64 = virt::handle_map(compute_desc as *mut c_void)
            .expect("handle_map failed") as cublasLtMatmulDesc_t
            as u64;
        let a_u64 =
            virt::handle_map(a as *mut c_void).expect("handle_map failed") as *const c_void as u64;
        let a_desc_u64 = virt::handle_map(a_desc as *mut c_void).expect("handle_map failed")
            as cublasLtMatrixLayout_t as u64;
        let b_u64 =
            virt::handle_map(b as *mut c_void).expect("handle_map failed") as *const c_void as u64;
        let b_desc_u64 = virt::handle_map(b_desc as *mut c_void).expect("handle_map failed")
            as cublasLtMatrixLayout_t as u64;
        let c_u64 =
            virt::handle_map(c as *mut c_void).expect("handle_map failed") as *const c_void as u64;
        let c_desc_u64 = virt::handle_map(c_desc as *mut c_void).expect("handle_map failed")
            as cublasLtMatrixLayout_t as u64;
        let d_u64 = virt::handle_map(d).expect("handle_map failed") as u64;
        let d_desc_u64 = virt::handle_map(d_desc as *mut c_void).expect("handle_map failed")
            as cublasLtMatrixLayout_t as u64;
        let workspace_u64 = virt::handle_map(workspace).expect("handle_map failed") as u64;
        let stream_u64 = virt::handle_map(stream as *mut c_void).expect("handle_map failed")
            as cudaStream_t as u64;

        let compute_type_size = get_scale_type_size(THREAD_SCALE_TYPE.with(|c| c.get()));
        let alpha_slice =
            unsafe { std::slice::from_raw_parts(alpha.cast::<u8>(), compute_type_size) };
        let beta_slice =
            unsafe { std::slice::from_raw_parts(beta.cast::<u8>(), compute_type_size) };

        let req = Request::with_args(
            ApiFuncName::FuncCublasltmatmul as u64,
            vec![
                Argument::from_ref(
                    &light_handle_u64,
                    ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
                ),
                Argument::from_ref(
                    &compute_desc_u64,
                    ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
                ),
                Argument::from_slice(alpha_slice, ArgumentFlag::ARG_IN),
                Argument::from_ref(&a_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(&a_desc_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(&b_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(&b_desc_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_slice(beta_slice, ArgumentFlag::ARG_IN),
                Argument::from_ref(&c_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(&c_desc_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(&d_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(&d_desc_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                unsafe { Argument::from_ptr(algo, ArgumentFlag::ARG_IN) },
                Argument::from_ref(
                    &workspace_u64,
                    ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
                ),
                Argument::from_ref(&workspace_size_in_bytes, ArgumentFlag::ARG_IN),
                Argument::from_ref(&stream_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
            ],
        );
        agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed")
    }

    fn cublasLtMatrixLayoutCreate(
        &self,
        mat_layout: *mut cublasLtMatrixLayout_t,
        type_x: cudaDataType,
        rows: u64,
        cols: u64,
        ld: i64,
    ) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtMatrixLayoutCreate");
        debug!("rows:{}, cols:{}, ld:{}", rows, cols, ld);

        let mut mat_layout_u64 = unsafe { *mat_layout } as u64;
        let req = Request::with_args(
            ApiFuncName::FuncCublasltmatrixlayoutcreate as u64,
            vec![
                Argument::from_mut(
                    &mut mat_layout_u64,
                    ArgumentFlag::ARG_OUT | ArgumentFlag::ARG_VIRT,
                ),
                Argument::from_ref(&type_x, ArgumentFlag::ARG_IN),
                Argument::from_ref(&rows, ArgumentFlag::ARG_IN),
                Argument::from_ref(&cols, ArgumentFlag::ARG_IN),
                Argument::from_ref(&ld, ArgumentFlag::ARG_IN),
            ],
        );
        let request_id = req.request_id();
        let res = agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed");

        unsafe {
            *mat_layout = mat_layout_u64 as cublasLtMatrixLayout_t;

            virt::handle_insert(*mat_layout as *mut c_void, *mat_layout as *mut c_void, 0)
                .expect("handle_insert failed");
            virt::req_id_vhandle_insert(request_id, *mat_layout as *mut c_void)
                .expect("req_id_vhandle_insert failed");
        }
        res
    }

    fn cublasLtMatrixLayoutDestroy(&self, mat_layout: cublasLtMatrixLayout_t) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtMatrixLayoutDestroy");

        let mat_layout_u64 = virt::handle_map(mat_layout as *mut c_void).expect("handle_map failed")
            as cublasLtMatrixLayout_t as u64;

        let req = Request::with_args(
            ApiFuncName::FuncCublasltmatrixlayoutdestroy as u64,
            vec![Argument::from_ref(
                &mat_layout_u64,
                ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
            )],
        );
        agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed")
    }

    fn cublasLtMatmulDescCreate(
        &self,
        matmul_desc: *mut cublasLtMatmulDesc_t,
        compute_type: cublasComputeType_t,
        scale_type: cudaDataType_t,
    ) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtMatmulDescCreate");
        debug!("matmul_desc:{:p}, **{:?}", matmul_desc, unsafe {
            *matmul_desc
        });

        THREAD_SCALE_TYPE.with(|c| c.set(scale_type));
        let mut matmul_desc_u64 = unsafe { *matmul_desc } as u64;

        let req = Request::with_args(
            ApiFuncName::FuncCublasltmatmuldesccreate as u64,
            vec![
                Argument::from_mut(
                    &mut matmul_desc_u64,
                    ArgumentFlag::ARG_OUT | ArgumentFlag::ARG_VIRT,
                ),
                Argument::from_ref(&compute_type, ArgumentFlag::ARG_IN),
                Argument::from_ref(&scale_type, ArgumentFlag::ARG_IN),
            ],
        );
        let request_id = req.request_id();
        let res = agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed");
        debug!("matmul_desc:{:p}, **{:x}", matmul_desc, matmul_desc_u64);

        unsafe {
            *matmul_desc = matmul_desc_u64 as cublasLtMatmulDesc_t;

            virt::handle_insert(*matmul_desc as *mut c_void, *matmul_desc as *mut c_void, 0)
                .expect("handle_insert failed");
            virt::req_id_vhandle_insert(request_id, *matmul_desc as *mut c_void)
                .expect("req_id_vhandle_insert failed");
        }
        res
    }

    fn cublasLtMatmulDescDestroy(&self, matmul_desc: cublasLtMatmulDesc_t) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtMatmulDescDestroy");
        THREAD_SCALE_TYPE.with(|c| c.set(0));

        let matmul_desc_u64 = virt::handle_map(matmul_desc as *mut c_void)
            .expect("handle_map failed") as cublasLtMatmulDesc_t
            as u64;

        let req = Request::with_args(
            ApiFuncName::FuncCublasltmatmuldescdestroy as u64,
            vec![Argument::from_ref(
                &matmul_desc_u64,
                ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
            )],
        );
        agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed")
    }

    fn cublasLtMatmulDescSetAttribute(
        &self,
        matmul_desc: cublasLtMatmulDesc_t,
        attr: cublasLtMatmulDescAttributes_t,
        buf: *const c_void,
        size_in_bytes: usize,
    ) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtMatmulDescSetAttribute");
        debug!("matmul_desc:{:p}, ", matmul_desc);

        let matmul_desc_u64 = virt::handle_map(matmul_desc as *mut c_void)
            .expect("handle_map failed") as cublasLtMatmulDesc_t
            as u64;

        debug!("size_in_byte:{}", size_in_bytes);
        let mut slice = unsafe { std::slice::from_raw_parts(buf.cast::<u8>(), size_in_bytes) };
        debug!("buf:{:p}, slice:{:?}", buf, slice);
        let mut slice_flag = ArgumentFlag::ARG_IN;
        if size_in_bytes == 8 {
            // device pointer!
            let mut _slice = [0u8; 8];
            _slice.copy_from_slice(&slice[..8]);
            debug!(
                "buf->u64, be:{:#x}, le:{:#x}(Little-endian!)",
                u64::from_be_bytes(_slice),
                u64::from_le_bytes(_slice)
            );
            // convert virt_map to &[u8] again!!
            let vh = u64::from_le_bytes(_slice) as *mut c_void;
            if virt::is_vhandle_valid(vh) {
                let mapped_buf = virt::handle_map(vh);
                slice = unsafe {
                    std::slice::from_raw_parts(std::ptr::from_ref(&mapped_buf).cast::<u8>(), 8)
                };
                slice_flag = ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT;
            }
        }
        let req = Request::with_args(
            ApiFuncName::FuncCublasltmatmuldescsetattribute as u64,
            vec![
                Argument::from_ref(
                    &matmul_desc_u64,
                    ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
                ),
                Argument::from_ref(&attr, ArgumentFlag::ARG_IN),
                Argument::from_slice(slice, slice_flag),
                Argument::from_ref(&size_in_bytes, ArgumentFlag::ARG_IN),
            ],
        );
        agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed")
    }

    fn cublasLtMatmulPreferenceCreate(
        &self,
        pref: *mut cublasLtMatmulPreference_t,
    ) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtMatmulPreferenceCreate");

        let mut pref_u64 = unsafe { *pref } as u64;

        let req = Request::with_args(
            ApiFuncName::FuncCublasltmatmulpreferencecreate as u64,
            vec![Argument::from_mut(
                &mut pref_u64,
                ArgumentFlag::ARG_OUT | ArgumentFlag::ARG_VIRT,
            )],
        );
        let request_id = req.request_id();
        let res = agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed");

        unsafe {
            *pref = pref_u64 as cublasLtMatmulPreference_t;

            virt::handle_insert(*pref as *mut c_void, *pref as *mut c_void, 0)
                .expect("handle_insert failed");
            virt::req_id_vhandle_insert(request_id, *pref as *mut c_void)
                .expect("req_id_vhandle_insert failed");
        }
        res
    }

    fn cublasLtMatmulPreferenceDestroy(&self, pref: cublasLtMatmulPreference_t) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtMatmulPreferenceDestroy");

        let pref_u64 = virt::handle_map(pref as *mut c_void).expect("handle_map failed")
            as cublasLtMatmulPreference_t as u64;

        let req = Request::with_args(
            ApiFuncName::FuncCublasltmatmulpreferencedestroy as u64,
            vec![Argument::from_ref(
                &pref_u64,
                ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
            )],
        );
        agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed")
    }

    fn cublasLtMatmulPreferenceSetAttribute(
        &self,
        pref: cublasLtMatmulPreference_t,
        attr: cublasLtMatmulPreferenceAttributes_t,
        buf: *const c_void,
        size_in_bytes: usize,
    ) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtMatmulPreferenceSetAttribute");
        debug!("buf:{:p}", buf);
        debug!("size_in_byte:{}", size_in_bytes);

        let pref_u64 = virt::handle_map(pref as *mut c_void).expect("handle_map failed")
            as cublasLtMatmulPreference_t as u64;

        let mut slice = unsafe { std::slice::from_raw_parts(buf.cast::<u8>(), size_in_bytes) };
        debug!("buf:{:p}, slice:{:?}", buf, slice);
        let mut slice_flag = ArgumentFlag::ARG_IN;
        if size_in_bytes == 8 {
            // device pointer!
            let mut _slice = [0u8; 8];
            _slice.copy_from_slice(&slice[..8]);
            debug!(
                "buf->u64, be:{:#x}, le:{:#x}(Little-endian!)",
                u64::from_be_bytes(_slice),
                u64::from_le_bytes(_slice)
            );
            // convert virt_map to &[u8] again!!
            let vh = u64::from_le_bytes(_slice) as *mut c_void;
            if virt::is_vhandle_valid(vh) {
                let mapped_buf = virt::handle_map(u64::from_le_bytes(_slice) as *mut c_void);
                slice = unsafe {
                    std::slice::from_raw_parts(std::ptr::from_ref(&mapped_buf).cast::<u8>(), 8)
                };
                slice_flag = ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT;
            }
        }
        let req = Request::with_args(
            ApiFuncName::FuncCublasltmatmulpreferencesetattribute as u64,
            vec![
                Argument::from_ref(&pref_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(&attr, ArgumentFlag::ARG_IN),
                Argument::from_slice(slice, slice_flag),
                Argument::from_ref(&size_in_bytes, ArgumentFlag::ARG_IN),
            ],
        );
        agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed")
    }

    fn cublasLtMatmulAlgoGetHeuristic(
        &self,
        light_handle: cublasLtHandle_t,
        operation_desc: cublasLtMatmulDesc_t,
        a_desc: cublasLtMatrixLayout_t,
        b_desc: cublasLtMatrixLayout_t,
        c_desc: cublasLtMatrixLayout_t,
        d_desc: cublasLtMatrixLayout_t,
        preference: cublasLtMatmulPreference_t,
        requested_algo_count: c_int,
        heuristic_results_array: *mut cublasLtMatmulHeuristicResult_t,
        return_algo_count: *mut c_int,
    ) -> cublasStatus_t {
        info!("[Hooked] api_name: cublasLtMatmulAlgoGetHeuristic");

        let light_handle_u64 = virt::handle_map(light_handle as *mut c_void)
            .expect("handle_map failed") as cublasLtHandle_t as u64;
        let operation_desc_u64 = virt::handle_map(operation_desc as *mut c_void)
            .expect("handle_map failed") as cublasLtMatmulDesc_t
            as u64;
        let a_desc_u64 = virt::handle_map(a_desc as *mut c_void).expect("handle_map failed")
            as cublasLtMatrixLayout_t as u64;
        let b_desc_u64 = virt::handle_map(b_desc as *mut c_void).expect("handle_map failed")
            as cublasLtMatrixLayout_t as u64;
        let c_desc_u64 = virt::handle_map(c_desc as *mut c_void).expect("handle_map failed")
            as cublasLtMatrixLayout_t as u64;
        let d_desc_u64 = virt::handle_map(d_desc as *mut c_void).expect("handle_map failed")
            as cublasLtMatrixLayout_t as u64;
        let preference_u64 = virt::handle_map(preference as *mut c_void).expect("handle_map failed")
            as cublasLtMatmulPreference_t as u64;

        let req = Request::with_args(
            ApiFuncName::FuncCublasltmatmulalgogetheuristic as u64,
            vec![
                Argument::from_ref(
                    &light_handle_u64,
                    ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
                ),
                Argument::from_ref(
                    &operation_desc_u64,
                    ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
                ),
                Argument::from_ref(&a_desc_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(&b_desc_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(&c_desc_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(&d_desc_u64, ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT),
                Argument::from_ref(
                    &preference_u64,
                    ArgumentFlag::ARG_IN | ArgumentFlag::ARG_VIRT,
                ),
                Argument::from_ref(&requested_algo_count, ArgumentFlag::ARG_IN),
                unsafe { Argument::from_mut_ptr(heuristic_results_array, ArgumentFlag::ARG_OUT) },
                unsafe { Argument::from_mut_ptr(return_algo_count, ArgumentFlag::ARG_OUT) },
            ],
        );
        agent::with_thread(|agent| agent.invoke_api::<cublasStatus_t>(req))
            .expect("call invoke_api failed")
    }
}
